package p48_事件监听器;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * 事件监听器
 * 实现ApplicationListener的bean可以作为事件监听器，加了@EventListener的方法的bean也可以
 * 对于第二种情况，实际spring会解析并将其变成一个ApplicationListener实现类注册给容器
 * 事件监听器本质就是一个个被容器管理的bean，将来事件发生时事件发布器会调用到这些bean,然后执行某些方法，典型的观察者模式
 */
@Configuration
public class _1_基于接口的监听器 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(_1_基于接口的监听器.class);
        context.getBean(MyService.class).doService();
        context.close();
    }

    /**
     * 自定义业务类，在业务类里通过发送事件的方式发送短信和邮件
     * 只需提供两个监听器来监听发送短信和邮件的事件，事件一旦发送，后续操作就交给监听器了，业务类就不用管了
     * 事件本身也是对象，所以需要提前定义事件对象(继承ApplicationEvent)，事件对象定义在最下面
     */
    @Component
    static class MyService {
        //事件发布器，本质是ApplicationContext
        @Autowired
        private ApplicationEventPublisher publisher;

        public void doService() {
            //使用事件发布器发送事件
            //发送短信事件
            publisher.publishEvent(new SmsEvent("MyService.doService"));
            //发送邮件事件
            publisher.publishEvent(new EmailEvent("MyService.doService"));
            /**
             * 根据监听器执行结果可以发现，只有发送短信代码执行完毕后，才会开始执行发送邮件的代码
             * 所以事件是同步的
             */
        }
    }

    /**
     * 事件发布了，必须有监听器来监听事件才行
     * ApplicationListener接口的实现就是监听器，该接口的泛型表示这个监听器感兴趣的事件类型
     * 下面的监听器只监听发送短信sms的事件
     */
    @Component
    static class SmsListener implements ApplicationListener<SmsEvent> {
        /**
         * 该bean注册到容器时，容器发现是ApplicationListener类型，就会将该bean注册为监听器
         * 一旦该监听器感兴趣的事件发生了，就会回调onApplicationEvent方法，并将事件对象作为方法参数
         */
        @Override
        public void onApplicationEvent(SmsEvent event) {
            try {
                System.out.println("正在发送短信...");
                Thread.sleep(1000);
                System.out.println("发送短信成功!!!");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 该监听器对发邮件事件感兴趣
     */
    @Component
    static class EmailListener implements ApplicationListener<EmailEvent> {
        /**
         * 该bean注册到容器时，容器发现是ApplicationListener类型，就会将该bean注册为监听器
         * 一旦该监听器感兴趣的事件发生了，就会回调onApplicationEvent方法，并将事件对象作为方法参数
         */
        @Override
        public void onApplicationEvent(EmailEvent event) {
            try {
                System.out.println("正在发送邮件...");
                Thread.sleep(1000);
                System.out.println("发送邮件成功!!!");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }


    //短信事件对象
    public static class SmsEvent extends ApplicationEvent {
        /**
         * @param source 事件来源，可以说明谁发送了这个事件
         */
        public SmsEvent(Object source) {
            super(source);
        }
    }

    //邮件事件对象
    public static class EmailEvent extends ApplicationEvent {
        public EmailEvent(Object source) {
            super(source);
        }
    }
}
